import {AstVisitor, Prog, FunctionCall, FunctionDecl, FunctionBody} from './nast';

/////////////////////////////////////////////////////////////////////////
// 语义分析
// 对函数调用做引用消解（Refrence Resolving），也就是找到函数的声明。

/**
 * 遍历AST。如果发现函数调用，就去找它的定义。
 */
export class RefResolver extends AstVisitor{
    prog: Prog|null = null;

    visitProg(prog:Prog):any{
        this.prog = prog;
        for(let x of prog.stmts){
            //根据stmt的类型，进行不同的处理
            let functionCall = x as FunctionCall;
            if (typeof functionCall.parameters === 'object'){
                this.resolveFunctionCall(prog, functionCall);
            }
            else{
                this.visitFunctionDecl(x as FunctionDecl);
            }
        }
    }

    //对函数体中的每一个函数调用，都进行引用消解
    visitFunctionBody(functionBody:FunctionBody):any{
        if(this.prog != null){
            for(let x of functionBody.stmts){
                this.resolveFunctionCall(this.prog, x);
            }
        }
    }

    //对于一个函数调用，查找函数声明，进行引用消解
    private resolveFunctionCall(prog: Prog, functionCall: FunctionCall){
        let functionDecl = this.findFunctionDecl(prog,functionCall.name);
        if (functionDecl != null){
            //非系统内置函数
            functionCall.definition = functionDecl;
        }
        else{
            if (functionCall.name.startsWith("nl.")){
                //除系统内置函数外，找不到引用，要报错
                console.log("Error: cannot find definition of function " + functionCall.name);
            }
        }
    }

    //在全部stmts中，根据名称查找函数声明
    private findFunctionDecl(prog:Prog, name:string):FunctionDecl|null{
        for(let x of prog?.stmts){
            let functionDecl = x as FunctionDecl;
            if (typeof functionDecl.body === 'object' &&
                functionDecl.name == name){
                return functionDecl;
            }
        }
        return null;
    }
}
